package org.bigjava.novelplatform.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.bigjava.novelplatform.common.enums.CommodityType;
import org.bigjava.novelplatform.common.enums.PayState;
import org.bigjava.novelplatform.common.enums.Subscribe;
import org.bigjava.novelplatform.common.exception.OrderException;
import org.bigjava.novelplatform.common.exception.UserActionException;
import org.bigjava.novelplatform.entity.*;
import org.bigjava.novelplatform.mapper.*;
import org.bigjava.novelplatform.service.CommonService;
import org.bigjava.novelplatform.service.OrderService;
import org.bigjava.novelplatform.vo.ChapterOrderVo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

import static org.bigjava.novelplatform.common.enums.CommodityType.BOOK_INTEGRAL;
import static org.bigjava.novelplatform.common.enums.CommodityType.CHAPTER;
import static org.bigjava.novelplatform.common.exception.ExceptionCodeMessage.SORRY_YOUR_CREDIT_IS_RUNNING_LOW;

/**
 * @author ykh
 * @create 2022-05-23 15:32
 */
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {

    @Resource
    private OrdersMapper ordersMapper;

    @Resource
    private BooksMapper booksMapper;

    @Resource
    private UsersMapper usersMapper;

    @Resource
    private WriterMapper writerMapper;

    @Resource
    private ChapterMapper chapterMapper;

    @Resource
    private PurchasedChapterMapper purchasedChapterMapper;

    @Resource
    private BookRackMapper bookRackMapper;

    @Resource
    private CommonService commonService;



    /**
     * 创建商品类型为章节的订单
     * @param userId
     * @param commodityId 商品id
     * @param counts      计件
     * @param unitPrice   单价
     * @param type 类型
     * @return
     */
    @Override
    public Orders createOrderChapter(Integer userId, Integer commodityId, Integer counts, BigDecimal unitPrice,
                                     CommodityType type) {
        Orders orders = new Orders();
        orders.setCreateTime(new Date());
        orders.setUserId(userId);
        orders.setCommodityType(type);
        orders.setCommodityId(commodityId);
        orders.setCounts(counts);
        orders.setUnitPrice(unitPrice);
        orders.setMoneyCount(unitPrice.multiply(BigDecimal.valueOf(counts)));
        //优惠金额 -- 略
        orders.setDiscount(new BigDecimal("0"));
        //实付  -- 略
        //新增消费积分 -- 略
        //支付状态 -- 略
        return orders;
    }

    /**
     * 购买单个章节
     *
     * @param userId
     * @param bookId
     * @param sort   章节顺序
     */
    @Override
    @Transactional(rollbackFor={Exception.class})
    public void purchaseSection(Integer userId, Integer bookId, Integer sort) {
        Books books = booksMapper.selectById(bookId);
        Writer writer = writerMapper.selectById(books.getWriterId());
        Users users = usersMapper.selectById(userId);
        Chapter chapter = chapterMapper.selectChapterOrder(bookId, sort);

        //章节定价
        BigDecimal price = books.getChapterUnitPrice();

        //TODO:优惠后价格,未完成
        BigDecimal chapterUnitPrice = preferentialInquiry(users, books, sort, CHAPTER);
        //余额
        BigDecimal tokensBalance = users.getTokensBalance();
        //余额不足
        if(tokensBalance.compareTo(chapterUnitPrice) < 0){
            throw new OrderException(SORRY_YOUR_CREDIT_IS_RUNNING_LOW);
        }
        //创建订单
        Orders orderChapter = createOrderChapter(userId, chapter.getChapterOrder(), 1, price,CHAPTER);
        //实付
        orderChapter.setActualPayment(chapterUnitPrice);
        //优惠金额
        orderChapter.setDiscount(price.subtract(chapterUnitPrice));
        //书籍的消费积分只有打赏才会获得
        orderChapter.setGainIntegral(0);
        //支付状态
        orderChapter.setPayState(PayState.PAID);
        //相减,余额
        BigDecimal subtract = tokensBalance.subtract(chapterUnitPrice);
        if(usersMapper.updateTokensBalanceById(userId,subtract)){
            //记录订单
            ordersMapper.insert(orderChapter);
            //修改用户购买记录
            List<PurchasedChapter> purchasedChapters = queryPurchasedChapters(userId, bookId);
            PurchasedChapter purchasedChapter = addChapter(purchasedChapters, userId, bookId, sort);
            if (purchasedChapter.getId() == null) {
                purchasedChapterMapper.insert(purchasedChapter);
            }else{
                purchasedChapterMapper.updateById(purchasedChapter);
            }
            //作者收益记录
            //手续费
            BigDecimal serviceCharge = price.multiply(books.getChapterServiceCharge());
            //收益
            BigDecimal profit = price.subtract(serviceCharge);
            writerMapper.increaseRevenue(profit,writer.getId());
            //书架消费记录
//            bookRackMapper.update()
            //TODO:计算消费积分，未完成
            Long aLong = calculateIntegral(1,price, userId,bookId, sort,CHAPTER);
            BookRack bookRack = bookRackMapper.selectBookRackByUserIdAndBookId(bookId, userId);
            if (bookRack == null) {
                bookRack = new BookRack();
                bookRack.setBookId(bookId);
                bookRack.setUserId(userId);
                bookRack.setContribution(aLong);
                bookRack.setJoinTime(new Date());
                bookRackMapper.insert(bookRack);
            }else{
                bookRackMapper.increaseContribution(userId,bookId,aLong);
            }
            //书籍信息收益记录
            booksMapper.increaseRevenue(profit,bookId);

        }
    }

    /**
     * 打赏书籍
     * 书架书架上的积分包括打赏和购买章节积分，
     * 书籍记录的积分只有打赏积分
     * @param userId
     * @param bookId
     * @param price
     * @param count 购买数量
     */
    @Override
    @Transactional(rollbackFor={RuntimeException.class})
    public void rewardBook(Integer userId, Integer bookId, BigDecimal price,Integer count) {
        Books books = booksMapper.selectById(bookId);
        Writer writer = writerMapper.selectById(books.getWriterId());
        Users users = usersMapper.selectById(userId);


        //优惠后价格
        BigDecimal chapterUnitPrice = preferentialInquiry(users, books, bookId, BOOK_INTEGRAL);
        //余额
        BigDecimal tokensBalance = users.getTokensBalance();
        //余额不足
        if(tokensBalance.compareTo(chapterUnitPrice) < 0){
            throw new UserActionException(SORRY_YOUR_CREDIT_IS_RUNNING_LOW);
        }

        Orders orderChapter = createOrderChapter(userId, bookId, count, price, BOOK_INTEGRAL);

        //实付
        orderChapter.setActualPayment(chapterUnitPrice);
        //优惠金额
        orderChapter.setDiscount(price.subtract(chapterUnitPrice));
        //书籍的消费积分
        orderChapter.setGainIntegral(price.intValue()*100);
        //支付状态
        orderChapter.setPayState(PayState.PAID);
        //相减,余额
        BigDecimal subtract = tokensBalance.subtract(chapterUnitPrice);
        if(usersMapper.updateTokensBalanceById(userId,subtract)){
            //记录订单
            ordersMapper.insert(orderChapter);
            //作者收益记录
            //手续费
            BigDecimal serviceCharge = price.multiply(books.getServiceCharge());
            //收益
            BigDecimal profit = price.subtract(serviceCharge);
            writerMapper.increaseRevenue(profit,writer.getId());

            //书架消费记录
            //TODO:计算消费积分，未完成
            Long aLong = calculateIntegral(count,price, userId,bookId, bookId,BOOK_INTEGRAL);

            BookRack bookRack = bookRackMapper.selectBookRackByUserIdAndBookId(bookId, userId);
            if (bookRack == null) {
                bookRack = new BookRack();
                bookRack.setBookId(bookId);
                bookRack.setUserId(userId);
                bookRack.setContribution(aLong);
                bookRack.setJoinTime(new Date());
                bookRackMapper.insert(bookRack);
            }else{
                bookRackMapper.increaseContribution(userId,bookId,aLong);
            }
            bookRackMapper.increaseContribution(userId,bookId,aLong);
            //书籍信息收益记录,//书籍的积分只在打赏时获取
            booksMapper.increaseEarningsOther(profit,bookId,aLong);
        }
    }




    /**
     * 购买多个章节
     * @param userId
     * @param bookId
     * @param startSort
     * @param endSort
     */
//    public void purchaseSections(Integer userId, Integer bookId, Integer startSort, Integer endSort) {
//        Books books = booksMapper.selectById(userId);
//
//        //单价
//        BigDecimal chapterUnitPrice = books.getChapterUnitPrice();
//        //
//
//    }


    /**
     * 计算消费积分
     * @param count 购买数
     * @param price 单价
     * @param userId 用户
     * @param id  章节序号/商品id
     * @param type 类型
     * @return
     */
    @Override
    public Long calculateIntegral(Integer count, BigDecimal price, Integer userId,Integer bookId, Integer id,
                                  CommodityType type){
        return count*10L;
    }

    /**
     * 查询优惠,并减扣
     * @param book 书籍 可以为空
     * @param startSort 书籍sort或商品id
     */
    @Override
    public BigDecimal preferentialInquiry(Users user, Books book, Integer startSort, CommodityType type){

        //TODO:优惠查询
        return book.getChapterUnitPrice();
    }

    /**
     * 查询当前章节或书籍是否有免费
     * @param startSort 当前章节序
     * @return true 免费
     */
    @Override
    public Boolean isFreeBookOrChapter(Integer userId, Integer bookId, Integer startSort){
        Integer integer = booksMapper.selectFreeChapter(bookId);
        if(integer == -1){
            return true;
        }else if(integer >= startSort){
            return true;
        }
        //TODO:其他免费
        return false;
    }

    /**
     * userId是否已购买bookId的第sort章
     * @return
     */
    @Override
    public Boolean isPurchased(Integer userId, Integer bookId, Integer sort){
        List<PurchasedChapter> purchasedChapters = queryPurchasedChapters(userId, bookId);
        for (PurchasedChapter purchasedChapter : purchasedChapters) {
            if(sort >= purchasedChapter.getBeginChapter() && sort <= purchasedChapter.getEndChapter()) {
                return true;
            }
        }
        return false;
    }

    /**
     * 是否订阅
     * @param userId
     * @param bookId
     * @return
     */
    @Override
    public Boolean isSubscribe(Integer userId, Integer bookId){
        BookRack bookRack = new BookRack();
        bookRack.setBookId(bookId);
        bookRack.setUserId(userId);
        QueryWrapper<BookRack> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("subscribe").eq("user_id", userId).eq("book_id", bookId);
        BookRack rack = bookRackMapper.selectOne(queryWrapper);
        Subscribe subscribe = rack.getSubscribe();
        return Subscribe.SIGNING.equals(subscribe);
    }

    /**
     * 获取章节内容
     * @param userId
     * @param bookId
     * @param chapterOrder
     * @return
     */
    @Override
    public ChapterOrderVo selectChapterOrder(Integer userId, Integer bookId, Integer chapterOrder) {
        boolean isFree = isFreeBookOrChapter(userId,bookId,chapterOrder);
        //免费无需购买
        if (!isFree){
            //是否购买
            Boolean purchased = isPurchased(userId, bookId, chapterOrder);
            if(purchased){
                ChapterOrderVo chapterOrderVo = commonService.selectChapterOrder(bookId, chapterOrder);
                chapterOrderVo.setPurchase(true);
                return chapterOrderVo;
            }
            //是否订阅
            if(isSubscribe(userId,bookId)){
                //购买章节
                try {
                    purchaseSection(userId,bookId,chapterOrder);
                } catch (Exception e) {
//                    log.error("");
                    if(e.getClass() == OrderException.class){
                        ChapterOrderVo chapterOrderVo = commonService.selectChapterOrder(bookId, chapterOrder);
                        chapterOrderVo.setPurchase(false);
                        ((OrderException) e).setData(chapterOrderVo);
                    }
                    throw e;
                }
                ChapterOrderVo chapterOrderVo = commonService.selectChapterOrder(bookId, chapterOrder);
                chapterOrderVo.setPurchase(true);
                return chapterOrderVo;
            }
        }else {
            ChapterOrderVo chapterOrderVo = commonService.selectChapterOrder(bookId, chapterOrder);
            chapterOrderVo.setPurchase(null);
            return chapterOrderVo;
        }
        ChapterOrderVo chapterOrderVo = commonService.selectChapterOrder(bookId, chapterOrder);
        chapterOrderVo.setPurchase(false);
        return chapterOrderVo;
    }



    /**
     * 查询已购买章节,顺序排列
     * @param userId
     * @return
     */
    @Override
    public List<PurchasedChapter> queryPurchasedChapters(Integer userId, Integer bookId){
        List<PurchasedChapter> purchasedChapters =
                toSequenceTable(purchasedChapterMapper.selectByUserIdAndBookId(userId, bookId));
        return purchasedChapters;
    }



    /**
     * 将从数据库查询到的数据整理为【begin end】-【begin end】-【begin end】顺序增长排列的
     *  为begin end的中位数排序，相当与为PurchasedChapter排序
     * @param plist
     * @return
     */
    @Override
    public List<PurchasedChapter> toSequenceTable(List<PurchasedChapter> plist) {
        ArrayList<Sort> median = new ArrayList<>();
        for (int i = 0; i < plist.size(); i++) {
            PurchasedChapter element = plist.get(i);
            median.add(
                    new Sort(
                            i, (element.getBeginChapter() + element.getEndChapter()) >> 1
                    )
            );
        }
        Collections.sort(median);
        ArrayList<PurchasedChapter> list = new ArrayList<>();
        for (Sort sort : median) {
            list.add(plist.get(sort.getIndex()));
        }
        return list;
    }

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    private class Sort implements Comparable<Sort> {
        private Integer index;
        private Integer median;

        @Override
        public int compareTo(Sort o) {
            return this.median - o.getMedian();
        }
    }

    /**
     * 获取需要添加的章节
     * 返回应当被插入/修改的章节实体
     * 1-99
     * <p>
     * 100-100
     * <p>
     * 102-130
     * @param list 应当保证 list是有序的
     *             org.bigjava.novelplatform.service.impl.OrderServiceImpl#toSequenceTable(java.util.List)
     */
    @Override
    public PurchasedChapter addChapter(List<PurchasedChapter> list, Integer userId, Integer bookId, Integer sort) {
        if (list != null && list.size() > 0) {
            if (sort < list.get(0).getBeginChapter()-1 || sort > list.get(list.size() - 1).getEndChapter()+1) {
                return new PurchasedChapter(null,userId,bookId,sort,sort,new Date(),0);
            }else if (sort == list.get(0).getBeginChapter()-1) {
                PurchasedChapter purchasedChapter = list.get(0);
                purchasedChapter.setBeginChapter(sort);
                purchasedChapter.setUpdateTime(new Date());
                return purchasedChapter;
            }else if(sort == list.get(list.size() - 1).getEndChapter()+1){
                PurchasedChapter purchasedChapter = list.get(list.size()-1);
                purchasedChapter.setEndChapter(sort);
                purchasedChapter.setUpdateTime(new Date());
                return purchasedChapter;
            }
        }else{
            return new PurchasedChapter(null,userId,bookId,sort,sort,new Date(),0);
        }
        Boolean flag = null;
        //所有区间，要保证section的值是顺序增长的，即list是顺序增长的
        ArrayList<Integer> section = new ArrayList<>();
        for (PurchasedChapter purchasedChapter : list) {
            Integer beginChapter = purchasedChapter.getBeginChapter();
            section.add(beginChapter);
            Integer endChapter = purchasedChapter.getEndChapter();
            section.add(endChapter);
            if (beginChapter > sort || endChapter < sort) {
                //一旦被不可购买记录过，就无法再此改变
                if (flag == null) {
                    //可以购买
                    flag = true;
                }
            } else {
                //已购买过
                log.info("{}不能重复购买书籍{}的第{}章", userId, bookId, sort);
                flag = false;
            }
        }
        if (flag == null) {
            log.error("{}从未购买过书籍{}的任何章节,与程序逻辑相悖", userId, bookId);
            throw new RuntimeException("与预计程序断言不符");
        }
        //一下正确的前提是section顺序增长的
        if (flag) {
            //计算sort在间隙的位置
            for (int i = 1; i < section.size() - 2; i += 2) {
                int clearance = section.get(i + 1) - section.get(i);
                if (clearance >= 1) {
                    if(clearance > 1){
                        if ( sort > section.get(i)+1 && sort < section.get(i + 1)-1) {
                            //购买的章节在这个间隙之中
                            return new PurchasedChapter(null,userId,bookId,sort,sort,new Date(),0);
                        }else if(sort == section.get(i)+1){
                            PurchasedChapter purchasedChapter = list.get(i >> 1);
                            purchasedChapter.setEndChapter(sort);
                            return purchasedChapter;
                        }else if(sort == section.get(i + 1)-1){
                            PurchasedChapter purchasedChapter = list.get((i+1) >> 1);
                            purchasedChapter.setBeginChapter(sort);
                            return purchasedChapter;
                        }
                    }
                } else {
                    throw new RuntimeException("与预计程序断言不符");
                }
            }
        }
        throw new RuntimeException("与预计程序断言不符");
    }


}
